package com.components.cachewebview

import android.annotation.SuppressLint
import android.content.Context
import android.text.TextUtils
import java.io.File
import java.io.InputStream
import java.net.URL
import java.util.*
import java.util.concurrent.CopyOnWriteArraySet

class AssetsLoader {

    private var mContext: Context? = null
    private var mAssetResSet: CopyOnWriteArraySet<String> = CopyOnWriteArraySet<String>()
    private var mDir: String = ""
    private var mCleared = false
    private var mIsSuffixMod = false

    companion object {
        @SuppressLint("StaticFieldLeak")
        @Volatile
        private var assetsLoader: AssetsLoader? = null
        fun getInstance(): AssetsLoader? {
            if (assetsLoader == null) {
                synchronized(AssetsLoader::class.java) {
                    if (assetsLoader == null) {
                        assetsLoader = AssetsLoader()
                    }
                }
            }
            return assetsLoader
        }
    }

    fun init(context: Context?): AssetsLoader {
        mContext = context
        mCleared = false
        return this
    }

    fun isAssetsSuffixMod(suffixMode: Boolean): AssetsLoader {
        mIsSuffixMod = suffixMode
        return this
    }

    private fun getUrlPath(url: String): String {
        var uPath: String = ""
        val u = URL(url)
        uPath = u.path
        if (uPath.startsWith("/")) {
            if (uPath.length == 1) {
                return uPath
            }
            uPath = uPath.substring(1)
        }
        return uPath
    }

    fun getResByUrl(url: String): InputStream? {
        val urlPath = getUrlPath(url)
        if (TextUtils.isEmpty(urlPath)) {
            return null
        }
        if (!mIsSuffixMod) {
            return if (TextUtils.isEmpty(mDir)) {
                getAssetFileStream(urlPath)
            } else {
                getAssetFileStream(mDir + File.separator + urlPath)
            }
        }
        if (mAssetResSet.size > 0) {
            mAssetResSet.forEach {
                if (urlPath.endsWith(it)) {
                    return if (TextUtils.isEmpty(mDir)) {
                        getAssetFileStream(it)
                    } else {
                        getAssetFileStream(mDir + File.separator + it)
                    }
                }
            }
        }
        return null
    }

    fun setDir(dir: String): AssetsLoader {
        mDir = dir
        return this
    }

    fun initData(): AssetsLoader {
        if (!mIsSuffixMod) {
            return this
        }
        if (mAssetResSet.size == 0) {
            Thread { initResourceNoneRecursion(mDir) }.start()
        }
        return this
    }

    fun clear() {
        mCleared = true
        if (mAssetResSet.size > 0) {
            mAssetResSet.clear()
        }
    }

    fun addAssetsFile(file: String) {
        val flag = mDir + File.separator
        var subFile = file
        if (!TextUtils.isEmpty(mDir)) {
            val pos = file.indexOf(flag)
            if (pos >= 0) {
                subFile = file.substring(pos + flag.length)
            }
        }
        mAssetResSet.add(subFile)
    }

    private fun initResourceNoneRecursion(dir: String): AssetsLoader {
        val list = LinkedList<String>()
        val resData = mContext?.assets?.list(dir)
        resData?.forEach {
            val sub = dir + File.separator + it
            val temp = mContext?.assets?.list(sub)
            if (temp?.size == 0) {
                addAssetsFile(sub)
            } else {
                list.add(sub)
            }
        }
        while (!list.isEmpty()) {
            if (mCleared) {
                break
            }
            val last = list.removeFirst()
            val tmp = mContext?.assets?.list(last)
            if (tmp?.size == 0) {
                addAssetsFile(last)
            } else {
                tmp?.forEach {
                    val tmp1 = mContext?.assets?.list(last + File.separator + it)
                    if (tmp1?.size == 0) {
                        addAssetsFile(last + File.separator + it)
                    } else {
                        list.add(last + File.separator + it)
                    }
                }
            }
        }
        return this
    }

    private fun getAssetFileStream(path: String): InputStream? {
        return mContext?.assets?.open(path)
    }
}